package com.example.demo.quartz.h3c;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo.exception.BaseServiceException;
import org.apache.commons.lang3.StringUtils;
import org.quartz.Job;
import org.quartz.JobKey;
import org.quartz.SchedulerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * ***************************************************************
 *
 * 定时器服务实现类
 *
 * @author lFW2156
 * @date 2018年1月31日下午5:26:32
 * @since v1.0.0
 ***************************************************************
 */
@Service
public class SysTimedTaskServiceImpl {
	private static final Logger LOGGER = LoggerFactory.getLogger(SysTimedTaskServiceImpl.class);
	@Autowired
	private ISysTimedTaskMapper sysTimedTaskMapper ;
	@Autowired
	private QuartzSupport quartzSupport;

	
	@Transactional(rollbackFor = { Exception.class })
	public void saveOrUpdate(SysTimedTaskDTO sysTimedTaskDTO) {
		SysTimedTask sysTimedTask = new SysTimedTask();
		Date now = new Date();
		String id = sysTimedTaskDTO.getId();
		if (id != null) {
			sysTimedTask = sysTimedTaskMapper.selectById(id);
			if (sysTimedTask == null) {
				LOGGER.error("数据库没有该ID对应的定时器!");
				throw new BaseServiceException("数据库没有该ID对应的定时器!");
			}
			String srcJobName = sysTimedTask.getJobName();
			String newJobName = sysTimedTaskDTO.getJobName().trim();
			if (!srcJobName.equals(newJobName)) {
				if (!isJobNameAvailable(newJobName)) {
					LOGGER.error("修改失败：已经存在名为[" + newJobName + "]的定时器!");
					throw new BaseServiceException("修改失败：已经存在名为[" + newJobName + "]的定时器!");
				}
			}
			if (sysTimedTask.getStart()) {
				LOGGER.error("修改失败：请先将定时任务关闭在修改!");
				throw new BaseServiceException("修改失败：请先将定时任务关闭在修改!");
			}
			BeanUtils.copyProperties(sysTimedTaskDTO, sysTimedTask,"createDate");
			sysTimedTask.setModifiedDate(now);
			sysTimedTaskMapper.updateById(sysTimedTask);
		} else {
			String jobName = sysTimedTaskDTO.getJobName();
			if (!isJobNameAvailable(jobName)) {
				LOGGER.error("创建失败：已经存在名为[" + jobName + "]的定时器!");
				throw new BaseServiceException("创建失败：已经存在名为[" + jobName + "]的定时器!");
			}
			String className = sysTimedTaskDTO.getClassName();
			if (!isClassNameExist(className)) {
				LOGGER.error("创建失败：不存在名为[" + className + "]的任务类!");
				throw new BaseServiceException("创建失败：不存在名为[" + className + "]的任务类!");
			}

			// 新建的定时器，默认要设置这三个值
			BeanUtils.copyProperties(sysTimedTaskDTO,sysTimedTask);
			sysTimedTask.setId(UUID.randomUUID().toString());
			sysTimedTask.setActive(true);
			sysTimedTask.setCreateDate(now);
			sysTimedTask.setStart(false);
			sysTimedTask.setModifiedDate(now);
			sysTimedTaskMapper.insert(sysTimedTask);
		}
	}


	
//	public IPage<SysTimedTask> listPageByDescription(PageModel pageModel) {
//		IPage<SysTimedTask> page = pageModel.page();
//		QueryWrapper<SysTimedTask> wrapper = pageModel.wrapper(true);
//		return super.page(page,wrapper);
//	}

	
	@Transactional(rollbackFor = { Exception.class })
	public void delete(String id) {
		if (StringUtils.isEmpty(id)) {
			throw new BaseServiceException("请选择删除的定时任务！");
		}
		SysTimedTask sysTimedTask = sysTimedTaskMapper.selectById(id);
		if (sysTimedTask.getStart()) {
			throw new BaseServiceException("删除定时任务前请先关闭定时任务！");
		}
		sysTimedTaskMapper.deleteById(id);
	}

	
	@Transactional(rollbackFor = Exception.class)
	public void batchDelete(List<String> ids) {
		if (ids.size() == 0 ) {
			throw new BaseServiceException("请选择要删除的定时任务!");
		}
		sysTimedTaskMapper.deleteBatchIds(ids);
	}


	
	public void executeCronJobForOnce(String id,String name) {
		SysTimedTask sysTimedTask = sysTimedTaskMapper.selectById(id);
		try {
			@SuppressWarnings("unchecked")
			Class<? extends Job> clazz = (Class<? extends Job>) Class.forName(sysTimedTask.getClassName());
			quartzSupport.executeForOnce(clazz,name);
		} catch (Exception ex) {
			LOGGER.error("立即生效失败：" + ex.getMessage());
			throw new BaseServiceException("立即生效失败！");
		}
	}

	
	@Transactional(rollbackFor = { Exception.class })
	public void startCronJob(String id) {
		SysTimedTask sysTimedTask = sysTimedTaskMapper.selectById(id);
		if (sysTimedTask.getActive()) {
			if(!sysTimedTask.getStart()){
				try {
					doQuartz(sysTimedTask);
					sysTimedTask.setStart(true);
					sysTimedTaskMapper.updateById(sysTimedTask);
				} catch (Exception ex) {
					LOGGER.error("开始任务失败：" + ex.getMessage());
					throw new BaseServiceException("开始定时任务失败!");
				}
			}
		} else {
			LOGGER.error("定时器未激活！");
			throw new BaseServiceException("定时器未激活！");
		}

	}

	
	@Transactional(rollbackFor = { Exception.class })
	public void stopCronJob(String id) {
		if (StringUtils.isEmpty(id)) {
			throw new BaseServiceException("请选择删除的定时任务！");
		}

		SysTimedTask sysTimedTask = sysTimedTaskMapper.selectById(id);
		if (!sysTimedTask.getStart()) {
			throw new BaseServiceException("定时任务已关闭，请勿重复关闭！");
		}
		JobKey jobKey = JobKey.jobKey(sysTimedTask.getJobName(), sysTimedTask.getJobGroup());
		try {
			quartzSupport.shutdown(jobKey);
			sysTimedTask.setStart(false);
			sysTimedTaskMapper.updateById(sysTimedTask);
		} catch (SchedulerException ex) {
			LOGGER.error("停止任务失败：" + ex.getMessage());
			throw new BaseServiceException("停止定时任务失败");
		}
	}

	
	public boolean isJobNameAvailable(String jobName) {
		try {
			SysTimedTask sysTimedTask = sysTimedTaskMapper.selectOne(new QueryWrapper<SysTimedTask>().eq("job_name", jobName));
			if (sysTimedTask == null) {
				return true;
			}
		} catch (Exception ex) {
			LOGGER.error("校验任务名称唯一性失败：" + ex.getMessage());
		}
		return false;

	}


	
	public boolean isClassNameExist(String className) {
		try {
			Class.forName(className);
			return true;
		} catch (ClassNotFoundException e) {
			return false;
		}

	}

	/**
	 * 执行定时器
	 * 
	 * @param sysTimedTask
	 * @throws SchedulerException
	 * @throws ClassNotFoundException
	 */
	@SuppressWarnings("unchecked")
	private void doQuartz(SysTimedTask sysTimedTask) throws SchedulerException, ClassNotFoundException {
		QuartzTaskDTO quartzTaskDTO = new QuartzTaskDTO();
		Class<? extends Job> quartzJob = (Class<? extends Job>) Class.forName(sysTimedTask.getClassName());
		quartzTaskDTO.setCronExpression(sysTimedTask.getCron());
		quartzTaskDTO.setDescription(sysTimedTask.getDescription());
		quartzTaskDTO.setJobGroup(sysTimedTask.getJobGroup());
		quartzTaskDTO.setJobName(sysTimedTask.getJobName());
		quartzTaskDTO.setQuartzJob(quartzJob);
		quartzSupport.createOrUpdateTask(quartzTaskDTO);
	}


    
    @Transactional(rollbackFor = { Exception.class })
    public void startCronJobByName(String name) {

        SysTimedTask sysTimedTask = sysTimedTaskMapper.selectOne(new QueryWrapper<SysTimedTask>().eq("job_name", name));
        if (sysTimedTask.getActive()) {
        	if(!sysTimedTask.getStart()){
				try {
					doQuartz(sysTimedTask);
					sysTimedTask.setStart(true);
					sysTimedTaskMapper.updateById(sysTimedTask);
				} catch (Exception ex) {
					LOGGER.error("开始任务失败：" + ex.getMessage());
					throw new BaseServiceException("开始定时任务失败!");
				}
			}
        } else {
            LOGGER.error("定时器未激活！");
            throw new BaseServiceException("定时器未激活！");
        }
         
    }

}
